﻿using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace MetalSoda
{
    /// <summary>
    /// SSB Route
    /// </summary>
    [Serializable]
    public class Route
    {
        /// <summary>
        /// Specifies the name of the remote service that this route points to.
        /// </summary>
        internal readonly Service FarService;

        /// <summary>
        /// Database hosting the receiving service.
        /// </summary>
        internal readonly DatabaseInfo FarDatabase;

        /// <summary>
        /// Database hosting the sending service.
        /// </summary>
        internal readonly DatabaseInfo LocalDatabase;

        /// <summary>
        /// Specifies the network address for this route. The next_hop_address specifies a TCP/IP address in the following format:
        /// TCP://{ dns_name | netbios_name | ip_address } : port_number
        /// </summary>
        public readonly string Address;

        /// <summary>
        /// Initializes a new instance of the <see cref="MetalSoda.Route"/> class.
        /// </summary>
        /// <param name="localDatabase">Database hosting the sending service.</param>
        /// <param name="farDatabase">Database hosting the receiving service.</param>
        /// <param name="farService">Name of the remote service that this route points to</param>
        /// <param name="policies">Route creationpolicies</param>
        public Route(DatabaseInfo localDatabase, DatabaseInfo farDatabase, Service farService,  object[] policies)
        {
            Authorization = "dbo";
            policies = policies ?? new object[0];
            var namingPolicy = policies.OfType<IRouteNamingPolicy>().FirstOrDefault() ?? new DefaultRouteNamingPolicy();
            this.LocalDatabase = localDatabase;
            this.FarService = farService;
            this.FarDatabase = farDatabase;
            Address = (farDatabase.Server == localDatabase.Server) ? "LOCAL" : farDatabase.Server.SSBEndPointAddress;
            Name = namingPolicy.CreateName(farDatabase, farService);
            if (string.IsNullOrWhiteSpace(Name)) { throw new InvalidOperationException(); }
            if (Name.Length > 128) { throw new InvalidOperationException(); }          
        }

        /// <summary>
        /// Route name (SQL Server SYSNAME)
        /// </summary>
        public string Name
        {
            get;
            private set;
        }

        public string Authorization { get; set; }


        public Guid? BrokerInstanceIdentifier
        {
            get { return FarDatabase.SSBIdentifier; }
        }


        public TimeSpan? RouteLifetime { get; set; }

        public override string ToString()
        {
            return new SQLScript.CreateRouteRuntimeTextTemplate(this).TransformText();
        }

        internal void Deploy()
        {
            using (var connection = new SqlConnection(this.LocalDatabase.ConnectionString))
            {
                var command = new SqlCommand(new SQLScript.CreateRouteRuntimeTextTemplate(this).TransformText(), connection);
                connection.Open();
                command.ExecuteNonQuery();
            }
        }
    }
}
